home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Special 16 / AMIGAplus Sonderheft 16 (1998)(ICP)(DE)[!].iso / pd / anwendungen / ispell-3.1.18src / ispell.c < prev    next >
C/C++ Source or Header  |  1995-07-03  |  28KB  |  1,034 lines

  1. #ifndef lint
  2. static char Rcs_Id[] =
  3.     "$Id: ispell.c 1.131  1995/01/08  23:23:39  geoff Exp $";
  4. #endif
  5.  
  6. #define MAIN
  7.  
  8. /*
  9.  * ispell.c - An interactive spelling corrector.
  10.  *
  11.  * Copyright (c), 1983, by Pace Willisson
  12.  *
  13.  * Copyright 1992, 1993, Geoff Kuenning, Granada Hills, CA
  14.  * All rights reserved.
  15.  *
  16.  * Redistribution and use in source and binary forms, with or without
  17.  * modification, are permitted provided that the following conditions
  18.  * are met:
  19.  *
  20.  * 1. Redistributions of source code must retain the above copyright
  21.  *    notice, this list of conditions and the following disclaimer.
  22.  * 2. Redistributions in binary form must reproduce the above copyright
  23.  *    notice, this list of conditions and the following disclaimer in the
  24.  *    documentation and/or other materials provided with the distribution.
  25.  * 3. All modifications to the source code must be clearly marked as
  26.  *    such.  Binary redistributions based on modified source code
  27.  *    must be clearly marked as modified versions in the documentation
  28.  *    and/or other materials provided with the distribution.
  29.  * 4. All advertising materials mentioning features or use of this software
  30.  *    must display the following acknowledgment:
  31.  *      This product includes software developed by Geoff Kuenning and
  32.  *      other unpaid contributors.
  33.  * 5. The name of Geoff Kuenning may not be used to endorse or promote
  34.  *    products derived from this software without specific prior
  35.  *    written permission.
  36.  *
  37.  * THIS SOFTWARE IS PROVIDED BY GEOFF KUENNING AND CONTRIBUTORS ``AS IS'' AND
  38.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  39.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  40.  * ARE DISCLAIMED.  IN NO EVENT SHALL GEOFF KUENNING OR CONTRIBUTORS BE LIABLE
  41.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  42.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  43.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  44.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  45.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  46.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47.  * SUCH DAMAGE.
  48.  */
  49.  
  50. /*
  51.  * $Log: ispell.c $
  52.  * Revision 1.131  1995/01/08  23:23:39  geoff
  53.  * Support variable hashfile suffixes for DOS purposes.  Report all the
  54.  * new configuration variables in the -vv switch.  Do some better error
  55.  * checking for mktemp failures.  Support the rename system call.  All of
  56.  * this is to help make DOS porting easier.
  57.  *
  58.  * Revision 1.130  1995/01/03  19:24:08  geoff
  59.  * When constructing a personal-dictioary name from the hash file name,
  60.  * don't stupidly include path directory components.
  61.  *
  62.  * Revision 1.129  1995/01/03  02:23:19  geoff
  63.  * Disable the setbuf call on BSDI systems, sigh.
  64.  *
  65.  * Revision 1.128  1994/10/26  05:12:28  geoff
  66.  * Include boundary characters in the list of characters to be tried in
  67.  * corrections.
  68.  *
  69.  * Revision 1.127  1994/10/25  05:46:07  geoff
  70.  * Allow the default dictionary to be specified by an environment
  71.  * variable (DICTIONARY) as well as a switch.
  72.  *
  73.  * Revision 1.126  1994/09/16  03:32:34  geoff
  74.  * Issue an error message for bad affix flags
  75.  *
  76.  * Revision 1.125  1994/07/28  05:11:36  geoff
  77.  * Log message for previous revision: fix backup-file checks to correctly
  78.  * test for exceeding MAXNAMLEN.
  79.  *
  80.  * Revision 1.124  1994/07/28  04:53:39  geoff
  81.  *
  82.  * Revision 1.123  1994/05/17  06:44:12  geoff
  83.  * Add support for controlled compound formation and the COMPOUNDONLY
  84.  * option to affix flags.
  85.  *
  86.  * Revision 1.122  1994/04/27  01:50:37  geoff
  87.  * Print MAX_CAPS in -vv mode.
  88.  *
  89.  * Revision 1.121  1994/03/16  03:49:10  geoff
  90.  * Fix -vv to display the value of NO_STDLIB_H.
  91.  *
  92.  * Revision 1.120  1994/03/15  06:24:28  geoff
  93.  * Allow the -t, -n, and -T switches to override each other, as follows:
  94.  * if no switches are given, the deformatter and string characters are
  95.  * chosen based on the file suffix.  If only -t/-n are given, the
  96.  * deformatter is forced but string cahracters come from the file suffix.
  97.  * If only -T is given, the deformatter is chosen based on the value
  98.  * given in the -T switch.  Finally, if both -T and -t/-n are given,
  99.  * string characters are controlled by -T and the deformatter by -t/-n.
  100.  *
  101.  * Revision 1.119  1994/03/15  05:58:07  geoff
  102.  * Get rid of a gcc warning
  103.  *
  104.  * Revision 1.118  1994/03/15  05:30:37  geoff
  105.  * Get rid of an unused-variable complaint by proper ifdeffing
  106.  *
  107.  * Revision 1.117  1994/03/12  21:26:48  geoff
  108.  * Correctly limit maximum name lengths for files that have directory paths
  109.  * included.  Also don't use a wired-in 256 for the size of the backup file
  110.  * name.
  111.  *
  112.  * Revision 1.116  1994/02/07  08:10:44  geoff
  113.  * Print GENERATE_LIBRARY_PROTOS in the -vv switch.
  114.  *
  115.  * Revision 1.115  1994/01/26  07:44:47  geoff
  116.  * Make yacc configurable through local.h.
  117.  *
  118.  * Revision 1.114  1994/01/25  07:11:44  geoff
  119.  * Get rid of all old RCS log lines in preparation for the 3.1 release.
  120.  *
  121.  */
  122.  
  123. #include "config.h"
  124. #include "ispell.h"
  125. #include "proto.h"
  126. #include "msgs.h"
  127.  
  128. #ifdef AMIGA
  129. extern char * Version_ID[];
  130. #else
  131. #include "version.h"
  132. #endif
  133.  
  134. #include <ctype.h>
  135. #include <sys/stat.h>
  136.  
  137. static void    usage P ((void));
  138. static void    initckch P ((char * wchars));
  139. int        main P ((int argc, char * argv[]));
  140. static void    dofile P ((char * filename));
  141. static void    update_file P ((char * filename, struct stat * statbuf));
  142. static void    expandmode P ((int printorig));
  143.  
  144. static char *    Cmd;
  145. static char *    LibDict = NULL;        /* Pointer to name of $(LIBDIR)/dict */
  146.  
  147. static void usage ()
  148.     {
  149.  
  150.     (void) fprintf (stderr, ISPELL_C_USAGE1, Cmd);
  151.     (void) fprintf (stderr, ISPELL_C_USAGE2, Cmd);
  152.     (void) fprintf (stderr, ISPELL_C_USAGE3, Cmd);
  153. #ifdef AMIGA
  154.     (void) fprintf (stderr, "       %s [-dfile | -pfile | -ffile | -Wn | -t | -n | -s | -B | -C | -P | -m | -Ttype] -r\n", Cmd);
  155. #endif
  156.     (void) fprintf (stderr, ISPELL_C_USAGE4, Cmd);
  157.     (void) fprintf (stderr, ISPELL_C_USAGE5, Cmd);
  158.     (void) fprintf (stderr, ISPELL_C_USAGE6, Cmd);
  159.     (void) fprintf (stderr, ISPELL_C_USAGE7, Cmd);
  160.     givehelp (0);
  161.     exit (1);
  162.     }
  163.  
  164. static void initckch (wchars)
  165.     char *        wchars;        /* Characters in -w option, if any */
  166.     {
  167.     register ichar_t    c;
  168.     char        num[4];
  169.  
  170.     for (c = 0; c < (ichar_t) (SET_SIZE + hashheader.nstrchars); ++c)
  171.     {
  172.     if (iswordch (c))
  173.         {
  174.         if (!mylower (c))
  175.         {
  176.         Try[Trynum] = c;
  177.         ++Trynum;
  178.         }
  179.         }
  180.     else if (isboundarych (c))
  181.         {
  182.         Try[Trynum] = c;
  183.         ++Trynum;
  184.         }
  185.     }
  186.     if (wchars != NULL)
  187.     {
  188.     while (Trynum < SET_SIZE  &&  *wchars != '\0')
  189.         {
  190.         if (*wchars != 'n'  &&  *wchars != '\\')
  191.         {
  192.         c = *wchars;
  193.         ++wchars;
  194.         }
  195.         else
  196.         {
  197.         ++wchars;
  198.         num[0] = '\0'; 
  199.         num[1] = '\0'; 
  200.         num[2] = '\0'; 
  201.         num[3] = '\0';
  202.         if (isdigit (wchars[0]))
  203.             {
  204.             num[0] = wchars[0];
  205.             if (isdigit (wchars[1]))
  206.             {
  207.             num[1] = wchars[1];
  208.             if (isdigit (wchars[2]))
  209.                 num[2] = wchars[2];
  210.             }
  211.             }
  212.         if (wchars[-1] == 'n')
  213.             {
  214.             wchars += strlen (num);
  215.             c = atoi (num);
  216.             }
  217.         else
  218.             {
  219.             wchars += strlen (num);
  220.             c = 0;
  221.             if (num[0])
  222.             c = num[0] - '0';
  223.             if (num[1])
  224.             {
  225.             c <<= 3;
  226.             c += num[1] - '0';
  227.             }
  228.             if (num[2])
  229.             {
  230.             c <<= 3;
  231.             c += num[2] - '0';
  232.             }
  233.             }
  234.         }
  235.         c &= NOPARITY;
  236.         if (!hashheader.wordchars[c])
  237.         {
  238.         hashheader.wordchars[c] = 1;
  239.         hashheader.sortorder[c] = hashheader.sortval++;
  240.         Try[Trynum] = c;
  241.         ++Trynum;
  242.         }
  243.         }
  244.     }
  245.     }
  246.  
  247. int main (argc, argv)
  248.     int        argc;
  249.     char *    argv[];
  250.     {
  251.     char *    p;
  252.     char *    cpd;
  253.     char **    versionp;
  254.     char *    wchars = NULL;
  255.     char *    preftype = NULL;
  256.     static char    libdictname[sizeof DEFHASH];
  257.     static char    outbuf[BUFSIZ];
  258.     int        argno;
  259.     int        arglen;
  260.  
  261.     Cmd = *argv;
  262.  
  263.     Trynum = 0;
  264.  
  265.     p = getenv ("DICTIONARY");
  266.     if (p != NULL)
  267.     {
  268. #ifdef AMIGA
  269.     if ((index (p, '/') != NULL) || (index (p, ':') != NULL))
  270. #else
  271.     if (index (p, '/') != NULL)
  272. #endif
  273.         (void) strcpy (hashname, p);
  274.     else
  275.         (void) sprintf (hashname, "%s/%s", LIBDIR, p);
  276.     p = rindex (p, '.');
  277.     if (p == NULL  ||  strcmp (p, HASHSUFFIX) != 0)
  278.         (void) strcat (hashname, HASHSUFFIX);
  279.     }
  280.     else
  281.     (void) sprintf (hashname, "%s/%s", LIBDIR, DEFHASH);
  282.  
  283.     cpd = NULL;
  284.  
  285.     argv++;
  286.     argc--;
  287.     while (argc && **argv == '-')
  288.     {
  289.     /*
  290.      * Trying to add a new flag?  Can't remember what's been used?
  291.      * Here's a handy guide:
  292.      *
  293.      * Used:
  294.      *
  295.      *    ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789
  296.      *    ^^^^       ^^^ ^  ^^ ^^
  297.      *    abcdefghijklmnopqrstuvwxyz
  298.      *    ^^^^^^     ^^^ ^ ^^^ ^^^
  299.      */
  300.     arglen = strlen (*argv);
  301.     switch ((*argv)[1])
  302.         {
  303.         case 'v':
  304.         if (arglen > 3)
  305.             usage ();
  306.         for (versionp = Version_ID;  *versionp;  )
  307.             {
  308.             p = *versionp++;
  309.             if (strncmp (p, "(#) ", 5) == 0)
  310.               p += 5;
  311.             (void) printf ("%s\n", p);
  312.             }
  313.  
  314. #ifndef AMIGA
  315.         if ((*argv)[2] == 'v')
  316.             {
  317.             (void) printf (ISPELL_C_OPTIONS_ARE);
  318. #ifdef USG
  319.             (void) printf ("\tUSG\n");
  320. #else /* USG */
  321.             (void) printf ("\t!USG (BSD)\n");
  322. #endif /* USG */
  323.             (void) printf ("\tBAKEXT = \"%s\"\n", BAKEXT);
  324.             (void) printf ("\tBINDIR = \"%s\"\n", BINDIR);
  325. #ifdef BOTTOMCONTEXT
  326.             (void) printf ("\tBOTTOMCONTEXT\n");
  327. #else /* BOTTOMCONTEXT */
  328.             (void) printf ("\t!BOTTOMCONTEXT\n");
  329. #endif /* BOTTOMCONTEXT */
  330. #if TERM_MODE == CBREAK
  331.             (void) printf ("\tCBREAK\n");
  332. #endif /* TERM_MODE */
  333.             (void) printf ("\tCC = \"%s\"\n", CC);
  334.             (void) printf ("\tCFLAGS = \"%s\"\n", CFLAGS);
  335. #ifdef COMMANDFORSPACE
  336.             (void) printf ("\tCOMMANDFORSPACE\n");
  337. #else /* COMMANDFORSPACE */
  338.             (void) printf ("\t!COMMANDFORSPACE\n");
  339. #endif /* COMMANDFORSPACE */
  340. #ifdef CONTEXTROUNDUP
  341.             (void) printf ("\tCONTEXTROUNDUP\n");
  342. #else /* CONTEXTROUNDUP */
  343.             (void) printf ("\t!CONTEXTROUNDUP\n");
  344. #endif /* CONTEXTROUNDUP */
  345.             (void) printf ("\tCONTEXTPCT = %d\n", CONTEXTPCT);
  346.             (void) printf ("\tCOUNTSUFFIX = \"%s\"\n", COUNTSUFFIX);
  347.             (void) printf ("\tDEFHASH = \"%s\"\n", DEFHASH);
  348.             (void) printf ("\tDEFINCSTR = \"%s\"\n", DEFINCSTR);
  349.             (void) printf ("\tDEFLANG = \"%s\"\n", DEFLANG);
  350.             (void) printf ("\tDEFNOBACKUPFLAG = %d\n",
  351.               DEFNOBACKUPFLAG);
  352.             (void) printf ("\tDEFPAFF = \"%s\"\n", DEFPAFF);
  353.             (void) printf ("\tDEFPDICT = \"%s\"\n", DEFPDICT);
  354.             (void) printf ("\tDEFTEXFLAG = %d\n", DEFTEXFLAG);
  355.             (void) printf ("\tEGREPCMD = \"%s\"\n", EGREPCMD);
  356.             (void) printf ("\tELISPDIR = \"%s\"\n", ELISPDIR);
  357.             (void) printf ("\tEMACS = \"%s\"\n", EMACS);
  358. #ifdef EQUAL_COLUMNS
  359.             (void) printf ("\tEQUAL_COLUMNS\n");
  360. #else /* EQUAL_COLUMNS */
  361.             (void) printf ("\t!EQUAL_COLUMNS\n");
  362. #endif /* EQUAL_COLUMNS */
  363. #ifdef GENERATE_LIBRARY_PROTOS
  364.             (void) printf ("\tGENERATE_LIBRARY_PROTOS\n");
  365. #else /* GENERATE_LIBRARY_PROTOS */
  366.             (void) printf ("\t!GENERATE_LIBRARY_PROTOS\n");
  367. #endif /* GENERATE_LIBRARY_PROTOS */
  368. #ifdef HAS_RENAME
  369.             (void) printf ("\tHAS_RENAME\n");
  370. #else /* HAS_RENAME */
  371.             (void) printf ("\t!HAS_RENAME\n");
  372. #endif /* HAS_RENAME */
  373.             (void) printf ("\tHASHSUFFIX = \"%s\"\n", HASHSUFFIX);
  374.             (void) printf ("\tHOME = \"%s\"\n", HOME);
  375. #ifdef IGNOREBIB
  376.             (void) printf ("\tIGNOREBIB\n");
  377. #else /* IGNOREBIB */
  378.             (void) printf ("\t!IGNOREBIB\n");
  379. #endif /* IGNOREBIB */
  380.             (void) printf ("\tINCSTRVAR = \"%s\"\n", INCSTRVAR);
  381.             (void) printf ("\tINPUTWORDLEN = %d\n", INPUTWORDLEN);
  382.             (void) printf ("\tLANGUAGES = \"%s\"\n", LANGUAGES);
  383.             (void) printf ("\tLIBDIR = \"%s\"\n", LIBDIR);
  384.             (void) printf ("\tLIBES = \"%s\"\n", LIBES);
  385.             (void) printf ("\tLINT = \"%s\"\n", LINT);
  386.             (void) printf ("\tLINTFLAGS = \"%s\"\n", LINTFLAGS);
  387. #ifndef REGEX_LOOKUP
  388.             (void) printf ("\tLOOK = \"%s\"\n", LOOK);
  389. #endif /* REGEX_LOOKUP */
  390.             (void) printf ("\tMAKE_SORTTMP = \"%s\"\n", MAKE_SORTTMP);
  391.             (void) printf ("\tMALLOC_INCREMENT = %d\n",
  392.               MALLOC_INCREMENT);
  393.             (void) printf ("\tMAN1DIR = \"%s\"\n", MAN1DIR);
  394.             (void) printf ("\tMAN1EXT = \"%s\"\n", MAN1EXT);
  395.             (void) printf ("\tMAN4DIR = \"%s\"\n", MAN4DIR);
  396.             (void) printf ("\tMAN4EXT = \"%s\"\n", MAN4EXT);
  397.             (void) printf ("\tMASKBITS = %d\n", MASKBITS);
  398.             (void) printf ("\tMASKTYPE = %s\n", MASKTYPE_STRING);
  399.             (void) printf ("\tMASKTYPE_WIDTH = %d\n", MASKTYPE_WIDTH);
  400.             (void) printf ("\tMASTERHASH = \"%s\"\n", MASTERHASH);
  401.             (void) printf ("\tMAXAFFIXLEN = %d\n", MAXAFFIXLEN);
  402.             (void) printf ("\tMAXCONTEXT = %d\n", MAXCONTEXT);
  403.             (void) printf ("\tMAXINCLUDEFILES = %d\n",
  404.               MAXINCLUDEFILES);
  405.             (void) printf ("\tMAXNAMLEN = %d\n", MAXNAMLEN);
  406.             (void) printf ("\tMAXPATHLEN = %d\n", MAXPATHLEN);
  407.             (void) printf ("\tMAXPCT = %d\n", MAXPCT);
  408.             (void) printf ("\tMAXSEARCH = %d\n", MAXSEARCH);
  409.             (void) printf ("\tMAXSTRINGCHARLEN = %d\n",
  410.               MAXSTRINGCHARLEN);
  411.             (void) printf ("\tMAXSTRINGCHARS = %d\n", MAXSTRINGCHARS);
  412.             (void) printf ("\tMAX_CAPS = %d\n", MAX_CAPS);
  413.             (void) printf ("\tMAX_HITS = %d\n", MAX_HITS);
  414.             (void) printf ("\tMAX_SCREEN_SIZE = %d\n",
  415.               MAX_SCREEN_SIZE);
  416.             (void) printf ("\tMINCONTEXT = %d\n", MINCONTEXT);
  417. #ifdef MINIMENU
  418.             (void) printf ("\tMINIMENU\n");
  419. #else /* MINIMENU */
  420.             (void) printf ("\t!MINIMENU\n");
  421. #endif /* MINIMENU */
  422.             (void) printf ("\tMINWORD = %d\n", MINWORD);
  423.             (void) printf ("\tMSDOS_BINARY_OPEN = 0x%x\n",
  424.               (unsigned int) MSDOS_BINARY_OPEN);
  425.             (void) printf ("\tMSGLANG = %s\n", MSGLANG);
  426. #ifdef NO_CAPITALIZATION_SUPPORT
  427.             (void) printf ("\tNO_CAPITALIZATION_SUPPORT\n");
  428. #else /* NO_CAPITALIZATION_SUPPORT */
  429.             (void) printf ("\t!NO_CAPITALIZATION_SUPPORT\n");
  430. #endif /* NO_CAPITALIZATION_SUPPORT */
  431. #ifdef NO_STDLIB_H
  432.             (void) printf ("\tNO_STDLIB_H\n");
  433. #else /* NO_STDLIB_H */
  434.             (void) printf ("\t!NO_STDLIB_H (STDLIB_H)\n");
  435. #endif /* NO_STDLIB_H */
  436. #ifdef NO8BIT
  437.             (void) printf ("\tNO8BIT\n");
  438. #else /* NO8BIT */
  439.             (void) printf ("\t!NO8BIT (8BIT)\n");
  440. #endif /* NO8BIT */
  441.             (void) printf ("\tNRSPECIAL = \"%s\"\n", NRSPECIAL);
  442.             (void) printf ("\tOLDPAFF = \"%s\"\n", OLDPAFF);
  443.             (void) printf ("\tOLDPDICT = \"%s\"\n", OLDPDICT);
  444. #ifdef PDICTHOME
  445.             (void) printf ("\tPDICTHOME = \"%s\"\n", PDICTHOME);
  446. #else /* PDICTHOME */
  447.             (void) printf ("\tPDICTHOME = (undefined)\n");
  448. #endif /* PDICTHOME */
  449.             (void) printf ("\tPDICTVAR = \"%s\"\n", PDICTVAR);
  450. #ifdef PIECEMEAL_HASH_WRITES
  451.             (void) printf ("\tPIECEMEAL_HASH_WRITES\n");
  452. #else /* PIECEMEAL_HASH_WRITES */
  453.             (void) printf ("\t!PIECEMEAL_HASH_WRITES\n");
  454. #endif /* PIECEMEAL_HASH_WRITES */
  455. #if TERM_MODE != CBREAK
  456.             (void) printf ("\tRAW\n");
  457. #endif /* TERM_MODE */
  458. #ifdef REGEX_LOOKUP
  459.             (void) printf ("\tREGEX_LOOKUP\n");
  460. #else /* REGEX_LOOKUP */
  461.             (void) printf ("\t!REGEX_LOOKUP\n");
  462. #endif /* REGEX_LOOKUP */
  463.             (void) printf ("\tREGLIB = \"%s\"\n", REGLIB);
  464.             (void) printf ("\tSIGNAL_TYPE = %s\n", SIGNAL_TYPE_STRING);
  465.             (void) printf ("\tSORTPERSONAL = %d\n", SORTPERSONAL);
  466.             (void) printf ("\tSTATSUFFIX = \"%s\"\n", STATSUFFIX);
  467.             (void) printf ("\tTEMPNAME = \"%s\"\n", TEMPNAME);
  468.             (void) printf ("\tTERMLIB = \"%s\"\n", TERMLIB);
  469.             (void) printf ("\tTEXINFODIR = \"%s\"\n", TEXINFODIR);
  470.             (void) printf ("\tTEXSPECIAL = \"%s\"\n", TEXSPECIAL);
  471. #ifdef TRUNCATEBAK
  472.             (void) printf ("\tTRUNCATEBAK\n");
  473. #else /* TRUNCATEBAK */
  474.             (void) printf ("\t!TRUNCATEBAK\n");
  475. #endif /* TRUNCATEBAK */
  476. #ifdef USESH
  477.             (void) printf ("\tUSESH\n");
  478. #else /* USESH */
  479.             (void) printf ("\t!USESH\n");
  480. #endif /* USESH */
  481.             (void) printf ("\tWORDS = \"%s\"\n", WORDS);
  482.             (void) printf ("\tYACC = \"%s\"\n", YACC);
  483.             }
  484. #endif /* !AMIGA */
  485.         exit (0);
  486.         break;
  487.         case 'n':
  488.         if (arglen > 2)
  489.             usage ();
  490.         tflag = 0;        /* nroff/troff mode */
  491.         deftflag = 0;
  492.         if (preftype == NULL)
  493.             preftype = "nroff";
  494.         break;
  495.         case 't':            /* TeX mode */
  496.         if (arglen > 2)
  497.             usage ();
  498.         tflag = 1;
  499.         deftflag = 1;
  500.         if (preftype == NULL)
  501.             preftype = "tex";
  502.         break;
  503.         case 'T':            /* Set preferred file type */
  504.         p = (*argv)+2;
  505.         if (*p == '\0')
  506.             {
  507.             argv++; argc--;
  508.             if (argc == 0)
  509.             usage ();
  510.             p = *argv;
  511.             }
  512.         preftype = p;
  513.         break;
  514.         case 'A':
  515.         if (arglen > 2)
  516.             usage ();
  517.         incfileflag = 1;
  518.         aflag = 1;
  519.         break;
  520.         case 'a':
  521.         if (arglen > 2)
  522.             usage ();
  523.         aflag++;
  524.         break;
  525. #ifdef AMIGA
  526.         case 'r':                            /* -r enables server mode */
  527.         if (arglen > 2)
  528.             usage ();
  529.         rflag=1;
  530.         break;
  531. #endif /* AMIGA */
  532.         case 'D':
  533.         if (arglen > 2)
  534.             usage ();
  535.         dumpflag++;
  536.         nodictflag++;
  537.         break;
  538.         case 'e':
  539.         if (arglen > 3)
  540.             usage ();
  541.         eflag = 1;
  542.         if ((*argv)[2] == 'e')
  543.             eflag = 2;
  544.         else if ((*argv)[2] >= '1'  &&  (*argv)[2] <= '4')
  545.             eflag = (*argv)[2] - '0';
  546.         else if ((*argv)[2] != '\0')
  547.             usage ();
  548.         nodictflag++;
  549.         break;
  550.         case 'c':
  551.         if (arglen > 2)
  552.             usage ();
  553.         cflag++;
  554.         lflag++;
  555.         nodictflag++;
  556.         break;
  557.         case 'b':
  558.         if (arglen > 2)
  559.             usage ();
  560.         xflag = 0;        /* Keep a backup file */
  561.         break;
  562.         case 'x':
  563.         if (arglen > 2)
  564.             usage ();
  565.         xflag = 1;        /* Don't keep a backup file */
  566.         break;
  567.         case 'f':
  568.         fflag++;
  569.         p = (*argv)+2;
  570.         if (*p == '\0')
  571.             {
  572.             argv++; argc--;
  573.             if (argc == 0)
  574.             usage ();
  575.             p = *argv;
  576.             }
  577.         askfilename = p;
  578.         if (*askfilename == '\0')
  579.             askfilename = NULL;
  580.         break;
  581.         case 'L':
  582.         p = (*argv)+2;
  583.         if (*p == '\0')
  584.             {
  585.             argv++; argc--;
  586.             if (argc == 0)
  587.             usage ();
  588.             p = *argv;
  589.             }
  590.         contextsize = atoi (p);
  591.         break;
  592.         case 'l':
  593.         if (arglen > 2)
  594.             usage ();
  595.         lflag++;
  596.         break;
  597. #ifndef USG
  598.         case 's':
  599.         if (arglen > 2)
  600.             usage ();
  601.         sflag++;
  602.         break;
  603. #endif
  604.         case 'S':
  605.         if (arglen > 2)
  606.             usage ();
  607.         sortit = 0;
  608.         break;
  609.         case 'B':        /* -B:  report missing blanks */
  610.         if (arglen > 2)
  611.             usage ();
  612.         compoundflag = COMPOUND_NEVER;
  613.         break;
  614.         case 'C':        /* -C:  compound words are acceptable */
  615.         if (arglen > 2)
  616.             usage ();
  617.         compoundflag = COMPOUND_ANYTIME;
  618.         break;
  619.         case 'P':        /* -P:  don't gen non-dict poss's */
  620.         if (arglen > 2)
  621.             usage ();
  622.         tryhardflag = 0;
  623.         break;
  624.         case 'm':        /* -m:  make all poss affix combos */
  625.         if (arglen > 2)
  626.             usage ();
  627.         tryhardflag = 1;
  628.         break;
  629.         case 'N':        /* -N:  suppress minimenu */
  630.         if (arglen > 2)
  631.             usage ();
  632.         minimenusize = 0;
  633.         break;
  634.         case 'M':        /* -M:  force minimenu */
  635.         if (arglen > 2)
  636.             usage ();
  637.         minimenusize = 2;
  638.         break;
  639.         case 'p':
  640.         cpd = (*argv)+2;
  641.         if (*cpd == '\0')
  642.             {
  643.             argv++; argc--;
  644.             if (argc == 0)
  645.             usage ();
  646.             cpd = *argv;
  647.             if (*cpd == '\0')
  648.             cpd = NULL;
  649.             }
  650.         LibDict = NULL;
  651.         break;
  652.         case 'd':
  653.         p = (*argv)+2;
  654.         if (*p == '\0')
  655.             {
  656.             argv++; argc--;
  657.             if (argc == 0)
  658.             usage ();
  659.             p = *argv;
  660.             }
  661. #ifdef AMIGA
  662.         if ((index (p, '/') != NULL) || (index (p, ':') != NULL))
  663. #else
  664.         if (index (p, '/') != NULL)
  665. #endif
  666.             (void) strcpy (hashname, p);
  667.         else
  668.             (void) sprintf (hashname, "%s/%s", LIBDIR, p);
  669.         if (cpd == NULL  &&  *p != '\0')
  670.             LibDict = p;
  671.         p = rindex (p, '.');
  672.         if (p != NULL  &&  strcmp (p, HASHSUFFIX) == 0)
  673.             *p = '\0';    /* Don't want ext. in LibDict */
  674.         else
  675.             (void) strcat (hashname, HASHSUFFIX);
  676.         p = rindex (LibDict, '/');
  677.         if (p != NULL)
  678.             LibDict = p + 1;
  679.         break;
  680.         case 'V':        /* Display 8-bit characters as M-xxx */
  681.         if (arglen > 2)
  682.             usage ();
  683.         vflag = 1;
  684.         break;
  685.         case 'w':
  686.         wchars = (*argv)+2;
  687.         if (*wchars == '\0')
  688.             {
  689.             argv++; argc--;
  690.             if (argc == 0)
  691.             usage ();
  692.             wchars = *argv;
  693.             }
  694.         break;
  695.         case 'W':
  696.         if ((*argv)[2] == '\0')
  697.             {
  698.             argv++; argc--;
  699.             if (argc == 0)
  700.             usage ();
  701.             minword = atoi (*argv);
  702.             }
  703.         else
  704.             minword = atoi (*argv + 2);
  705.         break;
  706.         default:
  707.         usage ();
  708.         }
  709.     argv++;
  710.     argc--;
  711.     }
  712.  
  713. #ifdef AMIGA
  714.     if (!argc  &&  !lflag  &&  !rflag && !aflag   &&  !eflag  &&  !dumpflag)
  715. #else
  716.     if (!argc  &&  !lflag  &&  !aflag   &&  !eflag  &&  !dumpflag)
  717. #endif /* AMIGA */
  718.     usage ();
  719.  
  720.     /*
  721.      * Because of the high cost of reading the dictionary, we stat
  722.      * the files specified first to see if they exist.  If at least
  723.      * one exists, we continue.
  724.      */
  725.     for (argno = 0;  argno < argc;  argno++)
  726.     {
  727.     if (access (argv[argno], 4) >= 0)
  728.         break;
  729.     }
  730. #ifdef AMIGA
  731.     if (argno >= argc  &&  !lflag  && !rflag && !aflag  &&  !eflag  &&  !dumpflag)
  732. #else
  733.     if (argno >= argc  &&  !lflag  &&  !aflag  &&  !eflag  &&  !dumpflag)
  734. #endif /* AMIGA */
  735.     {
  736.     (void) fprintf (stderr,
  737.       argc == 1 ? ISPELL_C_NO_FILE : ISPELL_C_NO_FILES);
  738.     exit (1);
  739.     }
  740.     if (linit () < 0)
  741.     exit (1);
  742.  
  743.     if (preftype != NULL)
  744.     {
  745.     prefstringchar =
  746.       findfiletype (preftype, 1, deftflag < 0 ? &deftflag : (int *) NULL);
  747.     if (prefstringchar < 0
  748.       &&  strcmp (preftype, "tex") != 0
  749.       &&  strcmp (preftype, "nroff") != 0)
  750.         {
  751.         (void) fprintf (stderr, ISPELL_C_BAD_TYPE, preftype);
  752.         exit (1);
  753.         }
  754.     }
  755.     if (prefstringchar < 0)
  756.     defdupchar = 0;
  757.     else
  758.     defdupchar = prefstringchar;
  759.  
  760.     if (compoundflag < 0)
  761.     compoundflag = hashheader.compoundflag;
  762.     if (tryhardflag < 0)
  763.     tryhardflag = hashheader.defhardflag;
  764.  
  765.     initckch(wchars);
  766.  
  767.     if (LibDict == NULL)    
  768.     {
  769.     (void) strcpy (libdictname, DEFHASH);
  770.     LibDict = libdictname;
  771.     p = rindex (libdictname, '.');
  772.     if (p != NULL  &&  strcmp (p, HASHSUFFIX) == 0)
  773.         *p = '\0';    /* Don't want ext. in LibDict */
  774.     }
  775.     if (!nodictflag)
  776.     treeinit (cpd, LibDict);
  777.  
  778. #ifdef AMIGA
  779.     if (rflag){                                /* Enter server mode */
  780.       servermode();
  781.       exit(0);
  782.     }
  783. #endif /* AMIGA */
  784.  
  785.     if (aflag)
  786.     {
  787.     askmode ();
  788.     treeoutput ();
  789.     exit (0);
  790.     }
  791.     else if (eflag)
  792.     {
  793.     expandmode (eflag);
  794.     exit (0);
  795.     }
  796.     else if (dumpflag)
  797.     {
  798.     dumpmode ();
  799.     exit (0);
  800.     }
  801.  
  802. #ifndef __bsdi__
  803.     setbuf (stdout, outbuf);
  804. #endif /* __bsdi__ */
  805.     if (lflag)
  806.     {
  807.     infile = stdin;
  808.     outfile = stdout;
  809.     checkfile ();
  810.     exit (0);
  811.     }
  812.  
  813.     terminit ();
  814.  
  815.     while (argc--)
  816.     dofile (*argv++);
  817.  
  818.     done (0);
  819.     /* NOTREACHED */
  820.     return 0;
  821.     }
  822.  
  823. static void dofile (filename)
  824.     char *    filename;
  825.     {
  826.     struct stat    statbuf;
  827.     char *    cp;
  828.  
  829.     currentfile = filename;
  830.  
  831.     /* See if the file is a .tex file.  If so, set the appropriate flags. */
  832.     tflag = deftflag;
  833.     if (tflag < 0)
  834.     tflag =
  835.       (cp = rindex (filename, '.')) != NULL  &&  strcmp (cp, ".tex") == 0;
  836.  
  837.     if (prefstringchar < 0)
  838.     {
  839.     defdupchar =
  840.       findfiletype (filename, 0, deftflag < 0 ? &tflag : (int *) NULL);
  841.     if (defdupchar < 0)
  842.         defdupchar = 0;
  843.     }
  844.  
  845.     if ((infile = fopen (filename, "r")) == NULL)
  846.     {
  847.     (void) fprintf (stderr, CANT_OPEN, filename);
  848.     (void) sleep ((unsigned) 2);
  849.     return;
  850.     }
  851.  
  852.     readonly = access (filename, 2) < 0;
  853.     if (readonly)
  854.     {
  855.     (void) fprintf (stderr, ISPELL_C_CANT_WRITE, filename);
  856.     (void) sleep ((unsigned) 2);
  857.     }
  858.  
  859.     (void) fstat (fileno (infile), &statbuf);
  860.     (void) strcpy (tempfile, TEMPNAME);
  861.     if (mktemp (tempfile) == NULL  ||  tempfile[0] == '\0'
  862.       ||  (outfile = fopen (tempfile, "w")) == NULL)
  863.     {
  864.     (void) fprintf (stderr, CANT_CREATE,
  865.       (tempfile == NULL  ||  tempfile[0] == '\0')
  866.         ? "temporary file" : tempfile);
  867.     (void) sleep ((unsigned) 2);
  868.     return;
  869.     }
  870.     (void) chmod (tempfile, statbuf.st_mode);
  871.  
  872.     quit = 0;
  873.     changes = 0;
  874.  
  875.     checkfile ();
  876.  
  877.     (void) fclose (infile);
  878.     (void) fclose (outfile);
  879.  
  880.     if (!cflag)
  881.     treeoutput ();
  882.  
  883.     if (changes && !readonly)
  884.     update_file (filename, &statbuf);
  885.     (void) unlink (tempfile);
  886.     }
  887.  
  888. static void update_file (filename, statbuf)
  889.     char *        filename;
  890.     struct stat *    statbuf;
  891.     {
  892.     char        bakfile[MAXPATHLEN];
  893.     int            c;
  894. #ifdef TRUNCATEBAK
  895.     int            maxlen;
  896. #endif /* TRUNCATEBAK */
  897.     char *        pathtail;
  898.  
  899.     if ((infile = fopen (tempfile, "r")) == NULL)
  900.     {
  901.     (void) fprintf (stderr, ISPELL_C_TEMP_DISAPPEARED, tempfile);
  902.     (void) sleep ((unsigned) 2);
  903.     return;
  904.     }
  905.  
  906. #ifdef TRUNCATEBAK
  907.     (void) strncpy (bakfile, filename, sizeof bakfile - 1);
  908.     bakfile[sizeof bakfile - 1] = '\0';
  909.     if (strcmp(BAKEXT, filename + strlen(filename) - sizeof BAKEXT - 1) != 0)
  910.     {
  911.     maxlen = MAXNAMLEN - strlen (BAKEXT);
  912.     pathtail = rindex (bakfile, '/');
  913.     if (pathtail == NULL)
  914.         pathtail = bakfile;
  915.     else
  916.         pathtail++;
  917.     if (strlen (pathtail) > MAXNAMLEN - sizeof BAKEXT - 1)
  918.         pathtail[MAXNAMLEN - sizeof BAKEXT -1] = '\0';
  919.     (void) strcat (pathtail, BAKEXT);
  920.     }
  921. #else
  922.     (void) sprintf (bakfile, "%.*s%s", (int) (sizeof bakfile - sizeof BAKEXT),
  923.       filename, BAKEXT);
  924. #endif
  925.  
  926.     pathtail = rindex (bakfile, '/');
  927.     if (pathtail == NULL)
  928.     pathtail = bakfile;
  929.     else
  930.     pathtail++;
  931.     if (strncmp (filename, bakfile, pathtail - bakfile + MAXNAMLEN) != 0)
  932.     (void) unlink (bakfile);    /* unlink so we can write a new one. */
  933. #ifdef HAS_RENAME
  934.     (void) rename (filename, bakfile);
  935. #else /* HAS_RENAME */
  936.     if (link (filename, bakfile) == 0)
  937.     (void) unlink (filename);
  938. #endif /* HAS_RENAME */
  939.  
  940.     /* if we can't write new, preserve .bak regardless of xflag */
  941.     if ((outfile = fopen (filename, "w")) == NULL)
  942.     {
  943.     (void) fprintf (stderr, CANT_CREATE, filename);
  944.     (void) sleep ((unsigned) 2);
  945.     return;
  946.     }
  947.  
  948.     (void) chmod (filename, statbuf->st_mode);
  949.  
  950.     while ((c = getc (infile)) != EOF)
  951.     (void) putc (c, outfile);
  952.  
  953.     (void) fclose (infile);
  954.     (void) fclose (outfile);
  955.  
  956.     if (xflag
  957.       &&  strncmp (filename, bakfile, pathtail - bakfile + MAXNAMLEN) != 0)
  958.     (void) unlink (bakfile);
  959.     }
  960.  
  961. static void expandmode (option)
  962.     int            option;        /* How to print: */
  963.                     /* 1 = expansions only */
  964.                     /* 2 = original line + expansions */
  965.                     /* 3 = original paired w/ expansions */
  966.                     /* 4 = add length ratio */
  967.     {
  968.     char        buf[BUFSIZ];
  969.     int            explength;    /* Total length of all expansions */
  970.     register char *    flagp;        /* Pointer to next flag char */
  971.     ichar_t        ibuf[BUFSIZ];
  972.     MASKTYPE        mask[MASKSIZE];
  973.     char        origbuf[BUFSIZ]; /* Original contents of buf */
  974.     char        ratiobuf[20];    /* Expansion/root length ratio */
  975.     int            rootlength;    /* Length of root word */
  976.     register int    temp;
  977.  
  978.     while (xgets (buf, sizeof buf, stdin) != NULL)
  979.     {
  980.     rootlength = strlen (buf);
  981.     if (buf[rootlength - 1] == '\n')
  982.       buf[--rootlength] = '\0';
  983.     (void) strcpy (origbuf, buf);
  984.     if ((flagp = index (buf, hashheader.flagmarker)) != NULL)
  985.         {
  986.         rootlength = flagp - buf;
  987.         *flagp++ = '\0';
  988.         }
  989.     if (option == 2  ||  option == 3  ||  option == 4)
  990.         (void) printf ("%s ", origbuf);
  991.     if (flagp != NULL)
  992.         {
  993.         if (flagp - buf > INPUTWORDLEN)
  994.         buf[INPUTWORDLEN] = '\0';
  995.         }
  996.     else
  997.         {
  998.         if ((int) strlen (buf) > INPUTWORDLEN - 1)
  999.         buf[INPUTWORDLEN] = '\0';
  1000.         }
  1001.     (void) fputs (buf, stdout);
  1002.     if (flagp != NULL)
  1003.         {
  1004.         (void) bzero ((char *) mask, sizeof (mask));
  1005.         while (*flagp != '\0'  &&  *flagp != '\n')
  1006.         {
  1007.         temp = CHARTOBIT ((unsigned char) *flagp);
  1008.         if (temp >= 0  &&  temp <= LARGESTFLAG)
  1009.             SETMASKBIT (mask, temp);
  1010.         else
  1011.             (void) fprintf (stderr, BAD_FLAG, (unsigned char) *flagp);
  1012.         flagp++;
  1013.         /* Accept old-format dicts with extra slashes */
  1014.         if (*flagp == hashheader.flagmarker)
  1015.             flagp++;
  1016.         }
  1017.         if (strtoichar (ibuf, buf, sizeof ibuf, 1))
  1018.         (void) fprintf (stderr, WORD_TOO_LONG (buf));
  1019.         explength = expand_pre (origbuf, ibuf, mask, option, "");
  1020.         explength += expand_suf (origbuf, ibuf, mask, 0, option, "");
  1021.         explength += rootlength;
  1022.         if (option == 4)
  1023.         {
  1024.         (void) sprintf (ratiobuf, " %f",
  1025.           (double) explength / (double) rootlength);
  1026.         (void) fputs (ratiobuf, stdout);
  1027.         (void) expand_pre (origbuf, ibuf, mask, 3, ratiobuf);
  1028.         (void) expand_suf (origbuf, ibuf, mask, 0, 3, ratiobuf);
  1029.         }
  1030.         }
  1031.     (void) putchar ('\n');
  1032.     }
  1033.     }
  1034.